package cn.apelx.store.service;

import cn.apelx.api.store.service.StoreDubboService;
import cn.apelx.store.domain.Store;
import cn.apelx.store.repository.StoreRepository;
import cn.apelx.tcc.common.domain.TccTransaction;
import cn.apelx.tcc.common.repository.TccTransactionRepository;
import io.seata.core.context.RootContext;
import io.seata.rm.tcc.api.BusinessActionContext;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.math.BigDecimal;
import java.util.Optional;
import java.util.Random;

/**
 * 仓库接口
 *
 * @author apelx
 * @since 2022-05-02
 */
@DubboService
@RefreshScope
public class StoreDubboServiceImpl implements StoreDubboService {

    @Autowired
    private StoreRepository storeRepository;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private TccTransactionRepository tccTransactionRepository;
    /**
     * 减库存
     *
     * @param storeId
     * @param subNum
     */
    @Override
    public void subStore(String storeId, BigDecimal subNum) {
        Optional<Store> optionalStore = storeRepository.findById(storeId);
        optionalStore.ifPresent(store -> {
            store.subStock(subNum);
            storeRepository.save(store);
        });
    }

    /**
     * 减库存
     *
     * @param actionContext tcc事务业务上下文
     * @param storeId
     * @param subNum
     */
    @Override
    public void subStoreTcc(BusinessActionContext actionContext, String storeId, BigDecimal subNum) {
        System.err.println("subStoreTcc ... actionContextMap: " + actionContext.getActionContext());

        // 先生成tcc事务控制记录,状态为try
        String xid = TccTransaction.genXid(actionContext.getXid(), actionContext.getActionContext());
        Optional<TccTransaction> tccOptional = tccTransactionRepository.findById(xid);
        TccTransaction tccTransaction = tccOptional.orElseGet(() -> {
            // 防悬挂
            TccTransaction tccTransaction1 = new TccTransaction(xid, TccTransaction.Status.INIT);
            tccTransactionRepository.save(tccTransaction1);
            return tccTransaction1;
        });
        // 如果先执行了rollback,这里是空try 防悬挂
        if (!tccTransaction.commit()) {
            return;
        }

        Optional<Store> optionalStore = storeRepository.findById(storeId);
        optionalStore.ifPresent(store -> {
            store.subStock(subNum);
            storeRepository.save(store);
        });
        stringRedisTemplate.boundValueOps("store").increment();
    }

    @Override
    public void subStoreTccCommit(BusinessActionContext actionContext) {

    }

    @Override
    public void subStoreTccRollback(BusinessActionContext actionContext) {
        System.err.println("subStoreTccRollback ... actionContextMap: " + actionContext.getActionContext());

        String storeId = (String) actionContext.getActionContext("storeId");
        Integer subNum = (Integer) actionContext.getActionContext("subNum");
        System.err.println("subStoreTccRollback... storeId: " + storeId + ", subNum: " + subNum);


        // 找到这次事务记录的数据
        String xid = TccTransaction.genXid(actionContext.getXid(), actionContext.getActionContext());
        Optional<TccTransaction> optionalTcc = tccTransactionRepository.findById(xid);
        TccTransaction tccTransaction = optionalTcc.orElseGet(() -> {
            // 不存在就new一个，防悬挂(rollback比try先执行)
            TccTransaction tccTransaction1 = new TccTransaction(xid, TccTransaction.Status.ROLLED_BACKED);
            tccTransactionRepository.save(tccTransaction1);
            return tccTransaction1;
        });
        // 没有这次事务记录或已回滚过 则空回滚
        if (!tccTransaction.rollback()) {
            return;
        }

        // 反向补偿
        Optional<Store> optionalStore = storeRepository.findById(storeId);
        optionalStore.ifPresent(store -> {
            store.addStock(new BigDecimal(subNum));
            storeRepository.save(store);
        });
        stringRedisTemplate.boundValueOps("store").decrement();

        tccTransactionRepository.save(tccTransaction);
    }

    /**
     * 测试调用链路集成到zipkin
     *
     * @return
     */
    @Override
    public String getStore() {
        try {
            Thread.sleep(new Random().nextInt(2000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "仓库xxx";
    }

}
